<!DOCTYPE html>
<meta charset="utf-8">
<title>Transform Test</title>
<style>

th,
td {
  border: solid #ccc 1px;
}

</style>
<body>
<script src="../../d3.js"></script>
<script>

var outcome = d3.select("body").append("p");

var g = d3.select("body").append("svg")
    .attr("width", 10)
    .attr("height", 10)
  .append("g");

var results = d3.select("body").append("table")
    .style("display", "none");

results.append("tr").selectAll("th")
    .data(["Expected", "Actual", "Expected matrix", "Actual matrix"])
  .enter().append("th")
    .text(function(d) { return d; });

var el = g[0][0],
    v,
    m,
    a,
    b,
    failures = 0;

for (var tx = -10; tx <= 10; tx += 5) {
  for (var ty = -10; ty <= 10; ty += 5) {
    for (var r = -180; r <= 180; r += 15) {
      for (var skx = -45; skx <= 45; skx += 45) {
        for (var sx = -2; sx <= 2; sx++) {
          for (var sy = -2; sy <= 2; sy++) {
            v = "translate(" + tx + "," + ty + ")rotate(" + r + ")skewX(" + skx + ")scale(" + sx + "," + sy + ")";
            g.attr("transform", v);
            a = matrix(el);
            g.attr("transform", d3.transform(v));
            b = matrix(el);
            if (!deepEqual(a, b, 1e-6)) {
              failures++;
              results
                  .style("display", null)
                .append("tr").selectAll("td")
                  .data([v, d3.transform(v), a, b])
                .enter().append("td")
                  .text(function(d) { return d; });
            }
          }
        }
      }
    }
  }
}

outcome.text(failures ? failures + " failures" : "Success!");

function matrix(el) {
  var t = el.transform.baseVal.consolidate();
  if (t) {
    var m = t.matrix;
    return [m.a, m.b, m.c, m.d, m.e, m.f];
  }
  return null;
}

function deepEqual(actual, expected, epsilon) {
  epsilon = epsilon || 0;
  if (actual === expected) return true;
  if (actual == null || expected == null) return false;
  if (actual.length !== expected.length) return false;

  for (var i = 0; i < actual.length; i++) {
    if (Math.abs(actual[i] - expected[i]) > epsilon) return false;
  }
  return true;
}

</script>
